<?php
Cinnamon::loadClass('ICollection');

class ArrayCollection implements ICollection {
	protected $source;
	
	private $_field;
	private $_order;
	
	/**
	 * Creates an instance of ArrayCollection by using the specified source
	 * @param array $source
	 */
	public function __construct($source) {
		$this->source = $source;
		$this->_resetKeys();
	}
	
	private function _resetkeys() {
		$this->source = array_merge($this->source, array());
	}
	
	/**
	 * @see ICollection::filter()
	 */
	public function filter($filter) {
		if ( $filter instanceof IFilter ) {
			$filter = array(&$filter, 'filter');
			$filter->filter($this);
		} else if ( function_exists($filter) ) {
			$this->source = array_filter($this->source, $filter);
		}
		$this->_resetKeys();
		return $this;
	}
	
	/**
	 * @see ICollection::sort()
	 */
	public function sort($field, $order='ASC') {
		$this->_field = $field;
		$this->_order = $order;
		usort($this->source, array(&$this, '_sort'));
		return $this;
	}
	private function _sort($a, $b) {
		$afield = ( is_object($a) ) ? $a->{$this->_field} : $a[$this->_field];
		$bfield = ( is_object($b) ) ? $b->{$this->_field} : $b[$this->_field];
		if ( is_numeric($afield) && is_numeric($afield) )
			$b = $afield - $bfield;
		else
			$b = strcmp($afield, $bfield);
		if ( $this->_order == 'DESC' )
			$b = -$b;
		return $b;
	}
	
	/**
	 * @see ICollection::slice()
	 */
	public function slice($offset, $length) {
		$this->source = array_slice($this->source, $offset, $length);
		return $this;
	}
	
	/**
	 * @see ICollection::getItemAt()
	 */
	public function getItemAt($i) {
		return (object) $this->source[$i];
	}
	
	/**
	 * @see ICollection::getValueAt()
	 */
	public function getValueAt($i, $field) {
		$item = $this->getItemAt($i);
		return $item->{$field};
	}
	
	/**
	 * @see ICollection::size()
	 */
	public function size() {
		return count($this->source);
	}
	
	public function current() {
		$v = current($this->source);
		return ( $v == false ) ? $v : (object) $v;
	}
	
	public function next() {
		$v = next($this->source);
		return ( $v == false ) ? $v : (object) $v;
	}
	
	public function key() {
		return key($this->source);
	}
	
	public function rewind() {
		return reset($this->source);
	}
	
	public function valid() {
		return $this->current() !== false;
	}
}
?>